package authserver

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"sync"
	"time"
	"gitee.com/zxs-micro/zxs-micro-auth/grpc/authserver/model"
	"gitee.com/zxs-micro/zxs-micro-auth/grpc/authserver/tokenmem"
	"gitee.com/zxs-micro/zxs-micro-common/grpc/common"
	"gitee.com/zxs-micro/zxs-micro-common/log"
	"gitee.com/zxs-micro/zxs-micro-auth/protos/auth"
)

var signala *AuthService
var signalm sync.Mutex

func NewAuthServer(d time.Duration, t tokenmem.TokenMemImpl) *AuthService {
	if t == nil {
		panic("配置的token记录装置为空！")
		return nil
	}
	signalm.Lock()
	defer signalm.Unlock()
	if signala == nil {
		signala = new(AuthService)
		signala.TokenTime = d
		signala.tokenMem = t
	}
	return signala
}

type AuthService struct {
	common.CommonService
	TokenTime time.Duration
	tokenMem  tokenmem.TokenMemImpl
}

func (s *AuthService) Accept(ctx context.Context, in *auth.AuthAcceptRequest) (*auth.AuthAcceptResponse, error) {
	resp := new(auth.AuthAcceptResponse)
	resp.IsSuccess = s.checkAuth(in.AccessToken, in.RequestUrl)
	return resp, nil
}

func (s *AuthService) Login(ctx context.Context, in *auth.LoginRequest) (*auth.LoginResponse, error) {
	t, m := s.createToken(in.LoginAccount, in.LoginRole)
	//todo 需要验证当前用户已有的token数量，然后根据配置来决定是否能继续登录
	//fmt.Println(t)
	//todo token保存的格式还得进一步改进
	s.tokenMem.AddToken(t, m)
	return &auth.LoginResponse{
		IsSuccess: true,
		AuthToken: t,
	}, nil
}

func (s *AuthService) FindLoginUser(ctx context.Context, in *auth.FindLoginUserRequest) (*auth.FindLoginUserResponse, error) {
	t, err := s.tokenMem.GetToken(in.Token)
	if err != nil {
		return nil, err
	}
	return &auth.FindLoginUserResponse{
		Account:    t.Account,
		Role:       t.Role,
		Creator:    t.Creator,
		CreateTime: t.CreateTime.Unix(),
		LastTime:   t.LastTime.Unix(),
	}, nil
}

func (s *AuthService) createToken(account, role string) (string, *model.TokenModel) {
	m := model.TokenModel{
		Creator:    s.SelfId,
		CreateTime: time.Now(),
		LastTime:   time.Now().Add(s.TokenTime),
		Account:    account,
		Role:       role,
	}
	bs, _ := json.Marshal(m)
	//fmt.Println(string(bs))
	return base64.StdEncoding.EncodeToString(bs), &m
}

func (s *AuthService) checkAuth(token, url string) bool {
	m, err := s.tokenMem.GetToken(token)
	if err != nil {
		log.Log.Error("解析用户token失败！", err.Error())
		return false
	}

	if time.Now().After(m.LastTime) {
		log.Log.Error("用户token已失效")
		return false
	}
	log.Log.Infof("用户%s[角色%s]希望在%s访问%s\n", m.Account, m.Role, time.Now().Format("2006-01-02 15:04:05"), url)
	//todo 需要添加用户的角色访问url的权限验证
	return true
}
